# 导入必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.metrics import (classification_report,
                             confusion_matrix,
                             accuracy_score,
                             ConfusionMatrixDisplay)
from sklearn.pipeline import Pipeline
import requests
from io import StringIO
import warnings

# 设置随机种子以保证结果可复现
np.random.seed(42)

# 忽略警告
warnings.filterwarnings('ignore')

# 设置绘图风格
plt.style.use('ggplot')
sns.set_style('whitegrid')


# ======================
# 数据加载与预处理
# ======================

def download_wine_data():
    """从网络下载葡萄酒数据集"""
    # 红葡萄酒数据集URL
    red_wine_url = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv"
    # 白葡萄酒数据集URL
    white_wine_url = "https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv"

    try:
        # 下载红葡萄酒数据
        red_response = requests.get(red_wine_url)
        red_response.raise_for_status()  # 检查请求是否成功
        red_wine = pd.read_csv(StringIO(red_response.text), delimiter=';')

        # 下载白葡萄酒数据
        white_response = requests.get(white_wine_url)
        white_response.raise_for_status()  # 检查请求是否成功
        white_wine = pd.read_csv(StringIO(white_response.text), delimiter=';')

        return red_wine, white_wine
    except requests.exceptions.RequestException as e:
        print(f"下载数据时出错: {e}")
        return None, None


def preprocess_data(red_wine, white_wine):
    """预处理葡萄酒数据"""
    # 添加葡萄酒类型列
    red_wine['type'] = 'red'
    white_wine['type'] = 'white'

    # 合并数据集
    wine = pd.concat([red_wine, white_wine], ignore_index=True)

    # 将质量评分转换为分类标签
    # 低(3-4), 中(5-6), 高(7-9)
    wine['quality_label'] = pd.cut(wine['quality'],
                                   bins=[2, 4, 6, 9],
                                   labels=['low', 'medium', 'high'])

    # 将类型转换为数值
    wine['type'] = wine['type'].map({'red': 0, 'white': 1})

    return wine  # 返回合并后的DataFrame


# 下载并预处理数据
red_wine, white_wine = download_wine_data()
if red_wine is None or white_wine is None:
    exit()

wine = preprocess_data(red_wine, white_wine)


# ======================
# 数据探索与可视化
# ======================

def explore_and_visualize_data(data):
    """数据探索与可视化"""
    print("\n=== 数据概览 ===")
    print(data.head())
    print("\n=== 数据信息 ===")
    print(data.info())
    print("\n=== 质量标签分布 ===")
    print(data['quality_label'].value_counts())

    # 1. 质量分布
    plt.figure(figsize=(14, 6))

    plt.subplot(1, 2, 1)
    sns.countplot(x='quality', data=data)
    plt.title('葡萄酒质量分布(原始评分)')

    plt.subplot(1, 2, 2)
    sns.countplot(x='quality_label', data=data)
    plt.title('葡萄酒质量分布(分类标签)')

    plt.tight_layout()
    plt.show()

    # 2. 红葡萄酒和白葡萄酒的质量比较
    plt.figure(figsize=(10, 6))
    sns.boxplot(x='type', y='quality', data=data)
    plt.xticks([0, 1], ['红葡萄酒', '白葡萄酒'])
    plt.title('不同类型葡萄酒的质量比较')
    plt.show()

    # 3. 特征相关性热图
    plt.figure(figsize=(12, 8))
    corr = data.corr(numeric_only=True)
    sns.heatmap(corr, annot=True, fmt=".2f", cmap='coolwarm', center=0)
    plt.title('特征相关性热图')
    plt.show()

    # 4. 关键特征与质量的关系
    key_features = ['alcohol', 'volatile acidity', 'citric acid', 'sulphates']

    plt.figure(figsize=(14, 10))
    for i, feature in enumerate(key_features, 1):
        plt.subplot(2, 2, i)
        sns.boxplot(x='quality_label', y=feature, data=data)
        plt.title(f'{feature} vs 质量等级')
    plt.tight_layout()
    plt.show()


# 执行数据探索
explore_and_visualize_data(wine)

# ======================
# 建模准备
# ======================

# 分离特征和目标变量
X = wine.drop(['quality', 'quality_label'], axis=1)
y = wine['quality_label']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y)

# 创建预处理和建模的pipeline
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('classifier', SVC(kernel='rbf', random_state=42))
])


# ======================
# 模型训练与评估
# ======================

def train_and_evaluate_model(pipeline, X_train, y_train, X_test, y_test):
    """训练和评估模型"""
    # 训练模型
    pipeline.fit(X_train, y_train)

    # 预测
    y_pred = pipeline.predict(X_test)

    # 评估指标
    accuracy = accuracy_score(y_test, y_pred)
    print(f"\n模型准确率: {accuracy:.2f}")
    print("\n分类报告:")
    print(classification_report(y_test, y_pred))

    # 混淆矩阵
    cm = confusion_matrix(y_test, y_pred)
    disp = ConfusionMatrixDisplay(confusion_matrix=cm,
                                  display_labels=['low', 'medium', 'high'])
    disp.plot(cmap='Blues')
    plt.title('混淆矩阵')
    plt.show()

    return pipeline, y_pred


# 初始模型训练与评估
print("\n=== 初始SVM模型 ===")
model, y_pred = train_and_evaluate_model(pipeline, X_train, y_train, X_test, y_test)


# ======================
# 模型优化
# ======================

def optimize_model(X_train, y_train):
    """使用网格搜索优化模型"""
    param_grid = {
        'classifier__C': [0.1, 1, 10, 100],
        'classifier__gamma': [1, 0.1, 0.01, 0.001],
        'classifier__kernel': ['rbf', 'linear', 'poly']
    }

    grid_search = GridSearchCV(
        pipeline,
        param_grid,
        cv=5,
        scoring='accuracy',
        verbose=1,
        n_jobs=-1
    )

    grid_search.fit(X_train, y_train)

    print("\n最佳参数:", grid_search.best_params_)
    print("最佳交叉验证准确率:", grid_search.best_score_)

    return grid_search.best_estimator_


# 优化模型
print("\n=== 优化SVM模型 ===")
best_model = optimize_model(X_train, y_train)

# 评估优化后的模型
print("\n=== 优化后模型性能 ===")
best_model, y_pred_best = train_and_evaluate_model(best_model, X_train, y_train, X_test, y_test)


# ======================
# 特征重要性分析
# ======================

def analyze_feature_importance(X_train, y_train):
    """分析特征重要性"""
    # 使用线性核SVM来获取特征重要性
    linear_pipeline = Pipeline([
        ('scaler', StandardScaler()),
        ('classifier', SVC(kernel='linear', random_state=42))
    ])

    linear_pipeline.fit(X_train, y_train)

    # 获取特征重要性(系数的绝对值)
    importance = np.abs(linear_pipeline.named_steps['classifier'].coef_[0])
    feature_importance = pd.DataFrame({
        'Feature': X_train.columns,
        'Importance': importance
    }).sort_values('Importance', ascending=False)

    # 绘制特征重要性
    plt.figure(figsize=(10, 6))
    sns.barplot(x='Importance', y='Feature', data=feature_importance)
    plt.title('葡萄酒质量预测特征重要性(线性SVM)')
    plt.xlabel('重要性(系数绝对值)')
    plt.ylabel('特征')
    plt.show()

    return feature_importance


# 分析特征重要性
print("\n=== 特征重要性分析 ===")
feature_importance = analyze_feature_importance(X_train, y_train)
print("\n特征重要性排序:")
print(feature_importance)

# ======================
# 保存模型(可选)
# ======================

# 如果需要保存模型，可以使用joblib
# from joblib import dump
# dump(best_model, 'wine_quality_svm_model.joblib')